﻿

// -/-/-/                      Current TODO list                                  /-/-/-
// IDE:
// Own dialog "Save changed files?" like in visual studio
// CodeCompletion for Squirrel, Pawn, Lua & others (full list...)
// Windows 8 tests and adaptation
// Release to Windows(8) Store
// Folding for Pawn, Squirrel, php and others c-like
// Add CrashReporter with web report and minidump creation
// Implement AvalonDock to main window: http://avalondock.codeplex.com/ ?
// Find/replace in 'Selection'
// Get rid of initializations in class definitions (so initializations must be done only from constructors)!
// History of searches for find & replace dg
// Context menu for documents' TextBoxes
// Python scripts support (.py) + highlighting + compiler
// Help/info tip dialogs
// Fix squirrel compiler not working in Windows XP (compile issue?)
// Fix & optimize load (fix startup issues with NamedPipes usage) and re-write communicating between processes
// "Server" menu with server management tools
// Add Functions list tool window
// Add encryption system for script files (encrypting contents with AES key) - could be useful
// About dialog
// Settings dialog (+pawn compiler includes dir)
// Localize code completion function lists (and make them INI-file-based) - ResourceManager.GetLocalizedExternalResource(string relativeFileName)
// After opening a tab with document, focus to text box and display cursor (FIX)
// Detecting if when NEWLINE typed we need to add TAB offset for next line (like "if() \n \T")
// FIX IV:MP compiler sometimes fails (better to use source SQ.exe, with modified ivmp's sources).
// Fix ETab construction
// Add type for *.TXT/*.TEXT, and *.LOG file viewing (no edit, auto-update).
// FTP filesystem driver (so work with files on ftp will be easier) and embed file explorer
// Change most of static classes into non-static, to initialize them not in first referering to them, but then showing a loading splash screen.
// Single-instance mode, but possibility of different instances for different windows users, because currently it is impossible to open file in editor, if another user already running an instance. Open command will be sent to that other user...!

// GUI Editor:
// Saving & loading GUIs to files
// Renaming IDs of GUI elements
// Add support for all types of elements
// Resizing gui elements with mouse
// Selecting gui elements in gui workbench with ctlr or mouse selection rectangle
// Implement support for gui property "Rotation" (WPF Control rotation)
// Size of GUI editor workbench should not be equal to window(tab) size + scrol bars
// Custom backgrounds for GUI workbench ?
// Fix Button element background
// Add correct properties support

// Interface or styles:
// Move Color picker to WPF window
// Improve templates for TabPage (header), Menu and ContextMenu
// Make a dockable toolbox window for GUI editor (not context menu) like in Visual Studio
// Horizontal scroll between tabs in case of overflow (current overflow behavior is not cool)
// More interactive dialog of Web-Update-Check
// Dialog for "new file" with file types and icons
// Own mini-dialog/popup for Find/Replace (like in VS quick Find) and "Go to line"
// Disabling menu items instead of checking Tab type is document and etc.
// Language change (recreate window after localization changed) - so no restart will be required to apply language.

// ===========================================================================================================

/*
 * Project: IV:MP GUI Editor (http://code.google.com/p/ivmp-gui-editor)
 * Code license: GNU Lesser GPL (http://www.gnu.org/copyleft/lesser.html)
 * 
 * Authors: CrackHD
 * Description: Common definitions and etc.
 */

using System;
using System.IO;
using System.Text;
using System.Windows;

namespace IvmpEditor
{
    /// <summary>
    /// Represents an extension of supported file type
    /// </summary>
    public class DocumentFileExtension
    {
        public string Name,
            HighlightingScheme;                 // highlighting scheme(for avalonedit texteditor)
        public string[] Extensions;             // list of associtated extensions
        public bool HideInSaveAsDialog;

        public Type CompilerType, CodeCompletionType;
        ICompiler m_compilerInstance = null;
        ICodeCompletion m_codeCompletionInstance = null;

        public ICompiler Compiler
        {
            // If not initialized, create ICompiler instance
            get
            {
                if (m_compilerInstance == null)
                    return (ICompiler)Activator.CreateInstance(CompilerType,
                        new object[] { Directory.GetCurrentDirectory() });

                return m_compilerInstance;
            }
        }
        public ICodeCompletion CodeCompletion
        {
            get
            {
                if (m_codeCompletionInstance == null && CodeCompletionType != null)
                    m_codeCompletionInstance = (ICodeCompletion)Activator.CreateInstance(CodeCompletionType);

                return m_codeCompletionInstance;
            }
        }
        public string Extension
        {
            set
            {
                if (value.IndexOf(';') != -1)
                    Extensions = value.Split(';');
                else
                    Extensions = new string[] { value };
            }
        }

        public override string ToString()
        {
            // Returning filter for save/open file dialogs:
            var extensions = string.Empty;
            for (var i = 0; i < Extensions.Length; i++)
                extensions += '*' + Extensions[i] + (i != Extensions.Length - 1 ? ";" : null);
            return string.Format("{0} ({1})|{1}", Name, extensions);
        }
    }

    /// <summary>
    /// Supported file types and associated methods
    /// </summary>
    public static class SupportedFileTypes
    {
        #region Definitions
        public static DocumentFileExtension Any = new DocumentFileExtension()
        {
            Extension = ".*",
            HighlightingScheme = "Disabled",
            Name = "Any"
        };
        public static DocumentFileExtension Squirrel = new DocumentFileExtension()
        {
            Extension = ".nut",
            HighlightingScheme = "Squirrel",
            Name = "Squirrel code file",
            CompilerType = typeof(SquirrelCompiler),
            CodeCompletionType = typeof(CIvmpFunctions)
        };
        public static DocumentFileExtension Pawn = new DocumentFileExtension()
        {
            Extension = ".pwn",
            HighlightingScheme = "C++", // Using CPP's one because they are (should be) equal
            Name = "Pawn script source",
            CompilerType = typeof(PawnCompiler)
        };
        public static DocumentFileExtension Lua = new DocumentFileExtension()
        {
            Extension = ".lua",
            HighlightingScheme = "Lua",
            Name = "Lua script source",
            CompilerType = typeof(LuaCompiler)
        };
        public static DocumentFileExtension CSharp = new DocumentFileExtension()
        {
            Extension = ".cs",
            HighlightingScheme = "C#",
            Name = "C# code file"
        };
        public static DocumentFileExtension Cpp = new DocumentFileExtension()
        {
            Extension = ".cpp;.h;.c",
            HighlightingScheme = "C++",
            Name = "C/C++ code file"
        };
        public static DocumentFileExtension JavaScript = new DocumentFileExtension()
        {
            Extension = ".js",
            HighlightingScheme = "JavaScript",
            Name = "JavaScript code file"
        };
        public static DocumentFileExtension Java = new DocumentFileExtension()
        {
            Extension = ".java",
            HighlightingScheme = "Java",
            Name = "Java code file"
        };
        public static DocumentFileExtension Css = new DocumentFileExtension()
        {
            Extension = ".css",
            HighlightingScheme = "CSS",
            Name = "Cascade style sheet (CSS)"
        };
        public static DocumentFileExtension VBNet = new DocumentFileExtension()
        {
            Extension = ".vb;.vbs",
            HighlightingScheme = "VBNET",
            Name = "Visual Basic .NET"
        };
        public static DocumentFileExtension Html = new DocumentFileExtension()
        {
            Extension = ".html;.htm",
            HighlightingScheme = "HTML",
            Name = "HTML page"
        };
        public static DocumentFileExtension Xml = new DocumentFileExtension()
        {
            Extension = ".xml;.xaml;.xshd;.resx",
            HighlightingScheme = "XML",
            Name = "XML"
        };
        public static DocumentFileExtension Php = new DocumentFileExtension()
        {
            Extension = ".php;.php4;.php5",
            HighlightingScheme = "PHP",
            Name = "PHP source"
        };
        #region Other
        public static DocumentFileExtension IvmpGuiWindow = new DocumentFileExtension()
        {
            Extension = ".ivmpgui",
            HideInSaveAsDialog = true,
            Name = "IV:MP GUI window design"
        };
        /*public static DocumentFileExtension SqBinary = new DocumentFileExtension()
        {
            Extension = ".cnut;.sq",
            IsSpecialHandlingType = true,
            Name = "Squirrel (compiled) Binary"
        };
        public static DocumentFileExtension PawnBinary = new DocumentFileExtension()
        {
            Extension = ".amx",
            IsSpecialHandlingType = true,
            Name = "Pawn (compiled) Binary"
        };
        public static DocumentFileExtension LuaBinary = new DocumentFileExtension()
        {
            Extension = ".out",
            IsSpecialHandlingType = true,
            Name = "Lua (compiled) Binary"
        };*/
        #endregion
        #endregion

        public static DocumentFileExtension[] List = new DocumentFileExtension[]
        {
            Squirrel, Pawn, Lua,
            Cpp, CSharp, VBNet,
            Java, JavaScript,
            Html, Xml, Css, Php,

            IvmpGuiWindow,
        };

        public static DocumentFileExtension GetByExtension(string ext)
        {
            // Looping thru all extensions and comparing
            ext = ext.ToLower();
            foreach (var ex in List)
                foreach(var ex2 in ex.Extensions)
                    if(ex2.ToLower() == ext)
                        return ex;

            // Unknown/Any/default.
            return Any;
        }
        public static string GetFilterList(bool includeAnyType, bool includeAllSupported, bool includeSpecialHandlingExtensions)
        {
            var filter = string.Empty;

            foreach (var docType in List)
                if (includeSpecialHandlingExtensions || !docType.HideInSaveAsDialog)
                    filter += docType.ToString() + '|';

            if (includeAllSupported)
            {
                filter += "Any of supported file types|";
                foreach (var docType in List)
                    foreach (var ex in docType.Extensions)
                        filter += '*' + ex + ';';
                filter = filter.TrimEnd(';') + '|';
            }

            if (includeAnyType)
                filter += Any.ToString();

            return filter.TrimEnd('|');
        }
    }

    /// <summary>
    /// IDE command types
    /// </summary>
    public enum eIDECommand
    {
        Unknown,
        OpenFileAuto,
        OpenEmptyTab,
    }

    /// <summary>
    /// Other statics & constants
    /// </summary>
    public static class Common
    {
        public static readonly Version AppVersion = new Version(0, 2, 0, 13);
        public static string AppVersionString = AppVersion.ToString();
        public static readonly DirectoryInfo 
            DirUserAppData = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\IvmpGuiEditor"),
            DirCommonAppData = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\IvmpGuiEditor");

        public static StreamReader CreateStreamFromString(string str, Encoding encd)
        {
            var strBytes = encd.GetBytes(str);
            var stream = new MemoryStream(strBytes.Length);
            stream.Write(strBytes, 0, strBytes.Length);
            stream.Seek(0, SeekOrigin.Begin);
            return new StreamReader(stream, encd);
        }
        public static string IdeCommandToString(eIDECommand cmd, string arg = null)
        {
            return cmd.ToString() + (arg != null ? ' ' + arg : null);
        }
        public static eIDECommand IdeCommandFromString(string srcString, out string cmdArg)
        {
            var str = srcString.Split(' ');

            eIDECommand cmd;
            Enum.TryParse<eIDECommand>(str[0], out cmd);

            cmdArg = string.Empty;
            for (int i = 1; i < str.Length; i++)
                cmdArg += str[i] + (i != str.Length - 1 ? " " : null);
            return cmd;
        }
        public static bool OpenWebUrl(string httpUrlAddress, bool promptError = true)
        {
            try
            {
                System.Diagnostics.Process.Start(httpUrlAddress);
                return true;
            }
            catch (Exception ex)
            {
                if (promptError)
                    MessageBox.Show(string.Format(Properties.Resources.L_ErrorU, ex.Message), "Web URL", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
        }
        public static string ToAbsolutePath(string path, DirectoryInfo rootDir)
        {
            var sep = Path.DirectorySeparatorChar.ToString();
            if (path.StartsWith(sep))
                path = path.Substring(1, path.Length - 2);
            if (!Path.IsPathRooted(path))
            {
                var i = path.LastIndexOf(Path.DirectorySeparatorChar);
                path = rootDir.FullName + (i < path.Length - 1 ? sep : null) + path;
            }

            // This allows to use "../" in relative paths.
            var workDir = Directory.GetCurrentDirectory();
            Directory.SetCurrentDirectory(rootDir.FullName);
            path = Path.GetFullPath(path);
            Directory.SetCurrentDirectory(workDir);
            return path;
        }
        public static void ToAbsolutePath(ref string path, DirectoryInfo rootDir)
        {
            path = ToAbsolutePath(path, rootDir);
        }
        public static void DeleteDirectory(string dirPath)
        {
            // 1. Remove files inside
            var files = Directory.GetFiles(dirPath);
            foreach (var file in files)
                File.Delete(file);

            // 2. Remove folders inside (recursive call)
            var subDirs = Directory.GetDirectories(dirPath);
            foreach (var subDir in subDirs)
                DeleteDirectory(subDir);

            // 3. Remove dir itself:
            Directory.Delete(dirPath);
        }
        public static void DeleteDirectory(DirectoryInfo directory)
        {
            if (!directory.Exists)
                return;

            DeleteDirectory(directory.FullName);
        }
    }
}